package com.xzlf.config;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.xzlf.domain.JobTask;
import com.xzlf.service.JobTaskService;
import com.xzlf.service.NbsScheduled;
import com.xzlf.service.TFileService;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.Trigger;
import org.springframework.scheduling.TriggerContext;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import org.springframework.scheduling.support.CronTrigger;

import java.util.Date;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;

//@Configuration
@Slf4j
public class ScheduledConfig implements SchedulingConfigurer {

    @Autowired
    private Map<String, NbsScheduled> taskMap;

    @Autowired
    private RedissonClient redissonClient;

    @Autowired
    private TFileService tFileService;

    @Autowired
    private JobTaskService jobTaskService;

    @Value("${task.lock.key1}")
    private String lockKey1;

    @Value("${task.lock.key2}")
    private String lockKey2;

    @Value("${task.lock.key3}")
    private String lockKey3;

    @Value("${task.lock.value1}")
    private String lockValue1;

    @Value("${task.lock.value2}")
    private String lockValue2;

    @Value("${server.name}")
    private String serverName;

    @Value("${job.execute.enable}")
    private boolean isExecute;


    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        for (String taskKey : taskMap.keySet()) {
            JobTask jobTask = jobTaskService.getOne(new LambdaQueryWrapper<JobTask>()
                    .eq(JobTask::getJobName, taskKey));
            taskRegistrar.addTriggerTask(
                    () -> {
                        if (!isExecute) {
                            log.info("{}任务{}不执行",serverName,taskKey);
                            return;
                        }
                        //从RedissonClient取得Rlock实例
                        RLock rLock = redissonClient.getLock(taskKey);
                        try {
                            //尝试取锁，有效期为3s，到期后自动释放。如果取得锁继续执行。取锁失败则自旋。
                            //使用rlock.tryLock（）方法，此方法也为尝试取锁，并返回boolean结果
                            boolean lock = rLock.tryLock(2, 6, TimeUnit.SECONDS);
                            if (!lock) {
                                return;
                            }
                            System.out.println("获取key:" + taskKey);
                            NbsScheduled nbsScheduled = taskMap.get(taskKey);
                            nbsScheduled.execute();
                        } catch (Exception e) {
                            e.printStackTrace();
                        } finally {
                            try {
                                TimeUnit.SECONDS.sleep(4);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                            if (rLock.isLocked()) {// 是否还是锁定状态
                                if (rLock.isHeldByCurrentThread()) {// 是否是当前执行线程的锁
                                    log.info("我是：{}，完成了:{}，开始释放锁。", serverName, jobTask.getJobDesc());
                                    rLock.unlock();
                                }
                            } else {
                                log.info("我是：{}，没有抢到锁，无需释放。", serverName);
                            }
                        }
                    },
                    new Trigger() {
                        @Override
                        public Date nextExecutionTime(TriggerContext triggerContext) {
                            String jobCron = jobTaskService.getOne(new LambdaQueryWrapper<JobTask>()
                                    .eq(JobTask::getJobName, taskKey)).getJobCron();
                            CronTrigger cronTrigger = new CronTrigger(jobCron);
                            return cronTrigger.nextExecutionTime(triggerContext);
                        }
                    });
        }
    }
}
